/** @file ar_rpc.h
  *
  * @brief This file contains the artosyn rpc defines etc
  *
  *  Copyright (C) 2024, Artosyn Technologies. ALL RIGHTS RESERVED.
  *
  *  This Information is proprietary to Artosyn Technologies and MAY NOT
  *  be copied by any method or incorporated into another program without
  *  the express written consent of Artosyn. This Information or any portion
  *  thereof remains the property of Artosyn. The Information contained herein
  *  is believed to be accurate and Artosyn assumes no responsibility or
  *  liability for its use in any way and conveys no license or title under
  *  any patent or copyright and makes no representation or warranty that this
  *  Information is free from patent or copyright infringement.
  *
  */
#ifndef __AR_RPC_H__
#define __AR_RPC_H__

#include <linux/kernel.h>
#include <linux/netdevice.h>
#include "utils/ringbuffer.h"
#include "oal_drv.h"

/*===============Definitions in artosyn rpc===============*/

/** size of rx ringbuffer, assemble the pkt from bb socket */
#define RX_RINGBUFFER_SIZE     (128 * 1024)

typedef enum {
    so_open  = 0,
    so_write = 1,
    so_read  = 2,
    so_close = 3,

    so_query_len    = 0x90,
    so_set_tx_limit = 0x91,
    so_get_tx_limit = 0x92,

    so_user_base_start = 0xc0,
    so_user_base_end   = 0xff,
} so_cmd_opt;

typedef struct bb_sock_opt_t {
    u32 tx_buf_size;                                       /**<@attention 用于指定发送buffer的大小，创建的socket具备TX属性时有效*/
    u32 rx_buf_size;                                       /**<@attention 用于指定接收buffer的大小，创建的socket具备RX属性时有效*/
} bb_sock_opt_t;

typedef enum ar_rpc_state_e {
    AR_RPC_STATE_DOWN,
    AR_RPC_STATE_UP,
    AR_RPC_STATE_SLEEP,
    AR_RPC_STATE_STOP,
} ar_rpc_state_t;

struct ar_rpc {
    void *ar_handle;   //device module handler
    ringbuffer_t *rb;   //ringbuffer for rx socket datagram
    //todo: all sync code coverage recheck
    oal_lock *op_wr_spinlock;
    oal_lock *op_rd_spinlock;

    ar_rpc_state_t state;

    struct list_head session_socket_list;       /** List of session socket */

    //todo: all sync code coverage recheck
    spinlock_t op_spinlock;
};

/**
 * @brief usbpack中的固定长度
 *
 */
static const u32 data_offset = 1 + 4 + 4 + 4 + 4 + 1;
static const u32 fixpackbase = 1 + 4 + 4 + 4 + 4 + 1 + 1;
static const u32 datagram_offset = 1 + 4 + 1;
static const u32 datagram_len = 1 + 4 + 1 + 1;

#define RPC_PACKET_HEADER_LEN  18
#define RPC_SOCKET_HEADER_LEN  6
#define RPC_SOCKET_DATAGRAM_HEADER_LEN  8
#define RPC_PACKET_TAILER_LEN  1
#define RPC_SOCKET_DATAGRAM_TAILER_LEN  1

// socket option flags
#define BB_SOCK_FLAG_RX             (1 << 0)                    /**<@attention 指示socket传输方向为接收的bit位标志*/
#define BB_SOCK_FLAG_TX             (1 << 1)                    /**<@attention 指示socket传输方向为发送的bit位标志*/
#define BB_SOCK_FLAG_TROC           (1 << 2)                    /**<@attention 指示socket当基带连接时清空TX buffer中的历史数据（TX buffer reset on connect），仅芯片侧支持*/
#define BB_SOCK_FLAG_DATAGRAM       (1 << 3)                    /**<@attention 指示socket传输为数据包模式，仅host driver侧支持*/

typedef struct rpc_pack {
    union {
        struct {
            u32 subcmdid : 24;
            u32 domainid : 8;
        };
        u32 reqid;
    };
    u32 datalen;
    u32 msgid;
    int32_t  sta;
    union {
        u8* datapack; /// 注意这个有可能是不对齐的
        void*    data_v;
    };
} rpc_pack_t;

int unpack_socket_datagram_pack(unsigned char* buff, u32 bufflen, u32 *payload_len);
int make_rpc_pack2buff(unsigned char* buff, u32 len, rpc_pack_t* pack);
int unpack_usb_pack(unsigned char* buff, u32 bufflen, int* usedlen, rpc_pack_t* pack);
int make_rpc_pack2buff_head_only(unsigned char* buff, u32 len, rpc_pack_t* pack);
int make_rpc_pack2buff_no_copy(unsigned char* buff, u32 len, rpc_pack_t* pack);
int get_fix_usblen(void);
int get_usb_data_offset(void);

/*===================RPC API================*/
/**
 * @brief Init the artosyn rpc module.
 *
 * @param   handle  Refers to oal_handle.
 *
 * @return  N/A
 */
void *ar_rpc_init(void *handle);

/**
 * @brief Deinit the artosyn rpc module.
 *
 * @param   handle  Refers to oal_handle.
 *
 * @return  N/A
 */
void ar_rpc_deinit(void *handle);

/**
 * @brief Set the state of artosyn rpc as stop.
 *
 * @param   handle  Refers to oal_handle.
 *
 * @return  N/A
 */
void ar_rpc_state_stop(void *handle);

/**
 * @brief Set the state of artosyn rpc as up.
 *
 * @param   handle  Refers to oal_handle.
 *
 * @return  N/A
 */
void ar_rpc_state_up(void *handle);

/**
 * @brief Analyze the pkt and dump the info.
 *
 * @param   ar_rpc  Refers to struct ar_rpc.
 * @param   skb     skb with data
 *
 * @return  N/A
 */
void ar_rpc_hdr_print(void *ar_rpc, struct sk_buff *skb);

/**
 * @brief Process the skb and put to rx queue of net dev.
 *
 * @param   handle  Refers to struct oal_handle.
 * @param   skb     skb with data
 *
 * @return  N/A
 */
void ar_rpc_rx_pkt(void *handle, struct sk_buff *skb);

/**
 * @brief Assemble the rpc msg and send to bus.
 *
 * @param   phandle Refers to oal_handle.
 * @param   pack    rpc_pack_t with rpc info
 * @param   skb     skb with data
 *
 * @return  0 for success, otherwise fail.
 */
int ar_rpc_tx_msg(void* handle, rpc_pack_t *pack, struct sk_buff *skb);

/**
 * @brief Assemble the rpc pkt and send to bus.
 *
 * @param   phandle Refers to oal_handle.
 * @param   pack    rpc_pack_t with rpc info
 *
 * @return  0 for success, otherwise fail.
 */
int ar_rpc_tx_pkt(void* handle, rpc_pack_t *pack, struct sk_buff *skb, void *priv_data);

/**
 * @brief Assemble the rpc pkt. Headrom and tailroom should be reserved!
 *
 * @param   buff   Point to the buffer
 * @param   len    Length of the buffer
 *
 * @return  0 for success, otherwise fail.
 */
int make_datagram_pack2buff_nocopy(unsigned char* buff, u32 len);

#endif